#pragma once
#include <iostream>
#include <cstring>
#include <pthread.h>
#include <unistd.h>
#include <netinet/in.h>
#include <functional>
#include <arpa/inet.h>
#include <sys/types.h>          
#include <sys/socket.h>
#include <sys/wait.h>
#include "nocopy.hpp"
#include "InetAddr.hpp"
#include"log.hpp"
#include"threadpool.hpp"
static const int gsockfd = -1;
static const int gblcklog = 5;//默认监听的个数
using task_t = function<void(void)>;
using service_t = function<void(int sockfd,InetAddr Client)>;
class Server
{

public:
	Server(uint16_t localport,service_t service)
		:_localport(localport),_listensockfd(gsockfd),_isruning(false),_service(service)
	{};
	struct ServerData//这个结构体是为了方便线程通过void*拿到所有需要的参数
	{
	ServerData(int sockfd,Server* self,InetAddr client)
		:_sockfd(sockfd),_self(self),_client(client)
	{};
	int _sockfd;
	Server* _self;
	InetAddr _client;
	};
	void Init()
	{
		//1.创建listensockfd
		_listensockfd = socket(AF_INET,SOCK_STREAM,0);
		if(_listensockfd<0)
		{
			LOG(FATAL,"server socket create err\n");
			exit(1);
		};
		//2.bind localaddr 和 listensockfd
		struct sockaddr_in localaddr;
		memset(&localaddr,0,sizeof(localaddr));
		localaddr.sin_family =AF_INET;
		localaddr.sin_port=htons(_localport);
		localaddr.sin_addr.s_addr =INADDR_ANY;
		int n =bind(_listensockfd,reinterpret_cast<struct sockaddr*>(&localaddr),sizeof(localaddr));
		if (n < 0)
       	 	{
            		LOG(FATAL, "server bind error\n");
      		      exit(2);
       		 }
       		 LOG(DEBUG, "server init success\n");
		 //3.监听
		 if(::listen(_listensockfd,gblcklog)<0)
		 {
            		LOG(FATAL, "server listen error\n");
      		      exit(3);
		 }
       		 LOG(DEBUG, "server listen success\n");

	};
	void Start()
	{
		_isruning = true;
		while(_isruning)
		{
			//4.接收
			struct sockaddr_in clientaddr;
			socklen_t len = sizeof(clientaddr);
			int sockfd = accept(_listensockfd,(struct sockaddr*)&clientaddr,&len);
			if(sockfd<0)
			{
				LOG(WARNING,"server accept err\n");
				continue;//接收出错问题不算太大，不会要求程序立刻终止。
			};
			InetAddr Client(clientaddr);
			LOG(INFO, "get a new link, client info : %s, sockfd is : %d\n", Client.AddrStr().c_str(), sockfd);
			//5.实现业务
			//version-1  --不合格的版本->只允许一个用户使用，且只能一问一答
			//Service(sockfd,Client);
			//version-2 --多进程版本->资源消耗大，性能也不理想
		//
	//		pid_t id = fork();
	//		if(id==0)
	//		{
	//			//child
	//			close(_listensockfd);//建议关闭监听文件描述符，因为进程共享文件描述符，防止子进程的监听描述符监听
	//			if(fork()>0)
	//				exit(0);//子进程退出，避免父进程等待业务的执行
	//			//grandson
	//			Service(sockfd,Client);
	//			exit(0);//孙子进程只用于执行一次业务
	//		};
	//		//father
	//		close(sockfd);
	//		int n = waitpid(id,nullptr,0);
	//		if(n>0)
	//		{
	//			LOG(DEBUG,"wait sucess\n");
	//		};
	//		version-3 --多线程版本->最合适的一个版本
			pthread_t tid;
			ServerData* sd =new ServerData(sockfd,this,Client);
			pthread_create(&tid,nullptr,Execute,sd);
		//	version-4 --线程池版本->线程池并不适合长服务，因为线程设定了上限
		//	task_t t=std::bind(&Server::Service,this,sockfd,Client);
		//	threadpool<task_t>::GetInstance()->push(t);

		};
	}
	static void* Execute(void* args)//线程传参函数
	{
		pthread_detach(pthread_self());
		ServerData* sd = static_cast<ServerData*>(args);
		sd->_self->_service(sd->_sockfd,sd->_client);
		delete sd;
		return nullptr;
	};
//	void Service(int sockfd,InetAddr Client)
//	{
//		while(true)//长服务
//		{
//			//目前的业务就是最基础的read和write
//			char buffer[1024];//字节流当字符串使用
//			ssize_t n =read(sockfd,buffer,sizeof(buffer)-1);
//			if(n>0)
//			{
//				buffer[n] = 0;//恢复字符串
//				LOG(INFO, "get message from client %s, message: %s\n", Client.AddrStr().c_str(), buffer);
//				string echo ="[server echo]";
//				echo+=buffer;
//				write(sockfd,echo.c_str(),echo.size());
//			}
//			else if(n==0)
//			{
//				LOG(INFO, "client %s quit\n", Client.AddrStr().c_str());
//                		break;
//			}
//			else
//			{
//				 LOG(ERROR, "read error: %s\n", Client.AddrStr().c_str());
//                		break;
//			};
//
//		};
//		close(sockfd);
//
//
//	};



private:
	uint16_t _localport;
	int _listensockfd;
	bool _isruning;//这个参数在本程序作用不大，但是是服务器不可缺少的
	service_t _service;
};
